package com.hua.utility.encrypt;

import java.security.Key;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

public class EncryptionPBE {

	/**
	 * 支持以下任意一种算法
	 * 
	 * <pre>
	 * PBEWithMD5AndDES 
	 * PBEWithMD5AndTripleDES 
	 * PBEWithSHA1AndDESede
	 * PBEWithSHA1AndRC2_40
	 * </pre>
	 */
	public static final String KEY_PBEWITHMD5ANDDES = "PBEWithMD5AndDES";
	public static final String KEY_PBEWITHMD5ANDTRIPLEDES = "PBEWithMD5AndTripleDES";
	public static final String KEY_PBEWITHSHA1ANDDESEDE = "PBEWithSHA1AndDESede";
	public static final String KEY_PBEWITHSHA1ANDRC2_40 = "PBEWithSHA1AndRC2_40";

	private String encryptType = "PBEWithMD5AndDES";

	public String getEncryptType() {
		return encryptType;
	}

	public void setEncryptType(String encryptType) {
		if (KEY_PBEWITHMD5ANDDES.equalsIgnoreCase(encryptType)) {
			this.encryptType = KEY_PBEWITHMD5ANDDES;
		} else
			if (KEY_PBEWITHMD5ANDTRIPLEDES.equalsIgnoreCase(encryptType) || "TripleDES".equalsIgnoreCase(encryptType)) {
			this.encryptType = KEY_PBEWITHMD5ANDTRIPLEDES;
		} else if (KEY_PBEWITHSHA1ANDDESEDE.equalsIgnoreCase(encryptType)) {
			this.encryptType = KEY_PBEWITHSHA1ANDDESEDE;
		} else if (KEY_PBEWITHSHA1ANDRC2_40.equalsIgnoreCase(encryptType)) {
			this.encryptType = KEY_PBEWITHSHA1ANDRC2_40;
		} else {
			this.encryptType = KEY_PBEWITHMD5ANDDES;
		}
	}

	/**
	 * 盐初始化
	 * 
	 * @return
	 * @throws Exception
	 */
	public static byte[] initSalt() throws Exception {
		byte[] salt = new byte[8];
		Random random = new Random();
		random.nextBytes(salt);
		return salt;
	}

	/**
	 * 转换密钥<br>
	 * 
	 * @param password
	 * @return
	 * @throws Exception
	 */
	private Key toKey(String password) throws Exception {
		PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(encryptType);
		SecretKey secretKey = keyFactory.generateSecret(keySpec);

		return secretKey;
	}

	/**
	 * 加密
	 * 
	 * @param data
	 *            数据
	 * @param password
	 *            密码
	 * @param salt
	 *            盐
	 * @return
	 * @throws Exception
	 */
	public byte[] encrypt(byte[] data, String password, byte[] salt) throws Exception {

		Key key = toKey(password);

		PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
		Cipher cipher = Cipher.getInstance(encryptType);
		cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);

		return cipher.doFinal(data);

	}

	/**
	 * 解密
	 * 
	 * @param data
	 *            数据
	 * @param password
	 *            密码
	 * @param salt
	 *            盐
	 * @return
	 * @throws Exception
	 */
	public byte[] decrypt(byte[] data, String password, byte[] salt) throws Exception {

		Key key = toKey(password);

		PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);
		Cipher cipher = Cipher.getInstance(encryptType);
		cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

		return cipher.doFinal(data);

	}

}